#include <gtest/gtest.h>

#include <atomic>
#include <future>
#include <shared_mutex>
#include <thread>
#include <vector>

using namespace std::chrono_literals;

// 演示 std::shared_mutex 和 std::shared_lock：多个读者可并行持有共享锁，
// 写者必须等待所有读者释放后才能获取独占锁。
TEST(SharedMutexTest, ReadersCoexistWritersWait) {
    std::shared_mutex sm;
    int value = 0;

    // 统计当前活跃读者数及观察到的最大并发读者数。
    std::atomic<int> activeReaders{0};
    std::atomic<int> maxConcurrentReaders{0};

    auto reader = [&]() {
        std::shared_lock<std::shared_mutex> lock(sm); // 获取共享锁
        int current = activeReaders.fetch_add(1, std::memory_order_acq_rel) + 1;

        // 更新最大并发读者数
        int observed = maxConcurrentReaders.load(std::memory_order_relaxed);
        while (current > observed &&
               !maxConcurrentReaders.compare_exchange_weak(
                   observed, current,
                   std::memory_order_release,
                   std::memory_order_relaxed)) {
            // 自旋直到成功写入最大值
        }

        std::this_thread::sleep_for(5ms); // 模拟读操作耗时
        activeReaders.fetch_sub(1, std::memory_order_acq_rel);
    };

    std::promise<bool> writerSawZero;
    auto writerFuture = writerSawZero.get_future();

    // 写者线程稍后尝试获取独占锁，此时必须等所有读者释放。
    std::thread writer([&] {
        std::this_thread::sleep_for(10ms);
        std::unique_lock<std::shared_mutex> lock(sm); // 独占锁
        bool noReaders = (activeReaders.load(std::memory_order_acquire) == 0);
        value = 42; // 修改共享数据
        writerSawZero.set_value(noReaders);
    });

    // 启动多个读者
    std::vector<std::thread> readers;
    for (int i = 0; i < 4; ++i) {
        readers.emplace_back(reader);
    }

    for (auto& t : readers) {
        t.join();
    }
    writer.join();

    EXPECT_EQ(value, 42);                         // 写者成功更新
    EXPECT_TRUE(writerFuture.get());              // 获取独占锁时确实没有读者
    EXPECT_GE(maxConcurrentReaders.load(), 2);    // 观察到至少两个并发读者
}